﻿/*
 * LdRequestServerExtension.Add
 * 
 * initial implementation : 26.6.2013
 * last upd: 27.9.2013
 *
 * Copyright (c) Adam Sida, asida@centrum.cz.
 * All rights reserved.
 * 
 * for license see cz.uhul.DSMLv2.txt
 */
using System;
using System.Collections.Generic;
using cz.uhul.DSMLv2;


namespace cz.uhul.DSMLv2.Server.Sql
{



  public static partial class LdRequestServerExtension
  {





    public static LdAddResponse Execute(this LdAddRequest addReq)
    {

      LdDistinguishedName dn;
      bool isValid = false;

      if (!LdDistinguishedName.TryParse(addReq.DistinguishedName, out dn))
        return new LdAddResponse(
          LdResultCodeEnum.InvalidDNSyntax
          , "addRequest failed"
          , "invalid DN:" + addReq.DistinguishedName
        );

      if (string.IsNullOrEmpty(dn))
        return new LdAddResponse(
          LdResultCodeEnum.InvalidDNSyntax
          , "addRequest failed"
          , "invalid DN:[empty]"
        );

      if (addReq.ObjectClass.Count == 0)
        return new LdAddResponse(
          LdResultCodeEnum.InvalidAttributeSyntax
          , "addRequest failed"
          , "invalid request, objectClass missing for:" + addReq.DistinguishedName
        );

      try
      {
        //class modifier exists for non-instance only
        bool IsInstance = !addReq.Attributes.ContainsName("mod");
        string superiorClass = ResolveSuperiorClass(addReq.ObjectClass, IsInstance);

        //create entry
        isValid = LdDatabase.AddEntry(
          addReq.DistinguishedName
          ,superiorClass
          , dn.RDNValue, dn.SuperiorPath, IsInstance 
        );
      
        foreach (LdAttr a in addReq.Attributes)
          if (
            (a.Name.ToLower() == "objectclass" && !IsInstance)
            || a.Name.ToLower() != "objectclass"
          )
            if (a.Name.ToLower() != "objectclass")
              isValid |= LdDatabase.AddAttrValues(addReq.DistinguishedName, a.Name, a.Values);

            else
              foreach (string v in a.Values)
                if (
                  (a.Name.ToLower() == "objectclass" && v != superiorClass)
                  //|| a.Name.ToLower() != "objectclass"
                )
                  isValid |= LdDatabase.AddAttrValue(addReq.DistinguishedName, a.Name, v);

        if (isValid)
          return new LdAddResponse(LdResultCodeEnum.Success, null, null);

        else
        {
          LdDatabase.DeleteEntry(addReq.DistinguishedName);

          return new LdAddResponse(
            LdResultCodeEnum.ConstraintViolation
            , "addRequest failed"
            , "invalid request, some MUST attribute missing for:" + addReq.DistinguishedName
          );
        }

      }
      catch(Exception e)
      {
        //todo:LdDatabase.DeleteEntry(RootDSE, DistinguishedName);
        //or better rollback tran

        LdResultCodeEnum pickErr;

        if (e.Message.Contains("Cannot insert duplicate key"))
          pickErr = LdResultCodeEnum.EntryAlreadyExists;

        else
          pickErr = LdResultCodeEnum.OperationsError;

        return new LdAddResponse(pickErr, "addRequest failed for:" + addReq.DistinguishedName, e.Message);
      }

    }






    /// <summary>
    /// get superior class from list of objectClass attributes...
    /// when create classDef, abstract or structural can act as superior class
    /// when create instance, structural only is allowed as superior class  
    /// </summary>
    /// <param name="objectClasses">List of requested objectClass names</param>
    /// <param name="isInstance">indicates if request for class instance or class def</param>
    /// <returns></returns>
    public static string ResolveSuperiorClass(List<string> objectClasses, bool isInstance)
    {
      string mod = null, tmp = null;

      foreach (string cls in objectClasses)
      {
        //ask db for modifier...
        mod = LdDatabase.GetClassModifier(cls).ToUpper();

        if (mod == "STRUCTURAL" && isInstance)
          if (String.IsNullOrEmpty(tmp))
            tmp = cls;

          else
            throw new LdException("invalid class def, more than one structural");

        else if ((mod == "STRUCTURAL" || mod == "ABSTRACT") && !isInstance)
          if (String.IsNullOrEmpty(tmp))
            tmp = cls;

          else
            throw new LdException("invalid class def, more than one structural or abstract");

      }

      return tmp;

    }



  }

}